package com.coolingme.springframework.aop;

import com.coolingme.springframework.aop.aspect.MeAdviceV1;
import com.coolingme.springframework.aop.intercept.MeMethodInvocation;
import com.coolingme.springframework.aop.support.MeAdvisedSupport;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;

/**
 * 使用JDK生产代理类的工具
 *
 * @author wangyue
 * @date 2024/9/9 22:28
 */
public class MeJdkDynamicAopProxy implements MeAopProxy, InvocationHandler {

    private MeAdvisedSupport advisedSupport;

    public MeJdkDynamicAopProxy(MeAdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // --------------------------------------v2------------------------------------

        // 获取代理方法对应的切面通知拦截器链，这里的method是代理类的方法对象
        List<Object> chain = this.advisedSupport.getInterceptorsAndDynamicInterceptionAdvice(method, this.advisedSupport.getTargetClass());

        MeMethodInvocation mi = new MeMethodInvocation(proxy, this.advisedSupport.getTarget(), method, args, this.advisedSupport.getTargetClass(), chain);

        // ☆递归调用，AOP的精髓
        return mi.proceed();

        /*if ("toString".equals(method.getName())) {
            return method.invoke(this.advisedSupport.getTarget(), args);
        }*/

        // --------------------------------------v1------------------------------------
        /*// 获取代理方法对应的切面方法，这里的method是代理类的方法对象
        Map<String, MeAdviceV1> advices = this.advisedSupport.getAdvices(method, this.advisedSupport.getTargetClass());

        // 原本目标类就不需要代理此方法，直接调用目标类的方法
        if (null == advices) {
            return method.invoke(this.advisedSupport.getTarget(), args);
        }

        // 调用前置通知
        invokeAdivce(advices.get(this.advisedSupport.getAopConfig().getAspectBefore()));

        Object returnValue = null;
        try {
            returnValue = method.invoke(this.advisedSupport.getTarget(), args);
        } catch (Exception e) {
            e.printStackTrace();
            // 调用异常通知
            invokeAdivce(advices.get(this.advisedSupport.getAopConfig().getAspectAfterThrow()));
        }

        // 调用后置通知
        invokeAdivce(advices.get(this.advisedSupport.getAopConfig().getAspectAfter()));

        return returnValue;*/
    }

    private void invokeAdivce(MeAdviceV1 advice) {
        try {
            // 调用切面方法，先不传参
            advice.getAdviceMethod().invoke(advice.getAspect());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public Object getProxy() {
        return getProxy(this.getClass().getClassLoader());
    }

    @Override
    public Object getProxy(ClassLoader classLoader) {
        Object proxyInstance = Proxy.newProxyInstance(classLoader, this.advisedSupport.getTargetClass().getInterfaces(), this);
        return proxyInstance;
    }
}
